package com.peking.donations.base.util;

import java.math.BigDecimal;
import java.util.Random;

/**
 * <p>
 * 处理数字相关的帮助类。
 * 
 * 主要解决目前数据库存储的金额为double类型，导致计算（例如sum）后精度问题。 例如，100.6699999实际上代表的是100.67
 * 
 * @author hawk
 *
 */
public class DigitalUtil {
    private static final int DEF_DIV_SCALE = 2;
    
    private DigitalUtil() {

    }

    /**
     * 提供精确的加法运算。
     * 
     * @param v1
     *            被加数
     * @param v2
     *            加数
     * @return 两个参数的和
     */
    public static double add(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.add(b2).doubleValue();
    }

    /**
     * 提供精确的减法运算。
     * 
     * @param v1
     *            被减数
     * @param v2
     *            减数
     * @return 两个参数的差
     */
    public static double sub(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.subtract(b2).doubleValue();
    }

    /**
     * 提供精确的乘法运算。
     * 
     * @param v1
     *            被乘数
     * @param v2
     *            乘数
     * @return 两个参数的积
     */
    public static double mul(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.multiply(b2).doubleValue();
    }

    /**
     * 提供（相对）精确的除法运算，当发生除不尽的情况时，精确到 小数点以后2位，以后的数字截位。
     * 
     * @param v1
     *            被除数
     * @param v2
     *            除数
     * @return 两个参数的商
     */
    public static double div(double v1, double v2) {
        return div(v1, v2, DEF_DIV_SCALE);
    }

    /**
     * 提供（相对）精确的除法运算。当发生除不尽的情况时，由scale参数指 定精度，以后的数字截位。
     * 
     * @param v1
     *            被除数
     * @param v2
     *            除数
     * @param scale
     *            表示表示需要精确到小数点以后几位。
     * @return 两个参数的商
     */
    public static double div(double v1, double v2, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException("The scale must be a positive integer or zero");
        }
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.divide(b2, scale, BigDecimal.ROUND_DOWN).doubleValue();
    }

    /**
     * 提供精确的小数位截位处理（非四舍五入）。
     * 
     * @param v
     *            需要截位的数字
     * @param scale
     *            小数点后保留几位
     * @return 截位后的结果
     */
    public static double round(double v, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException("The scale must be a positive integer or zero");
        }
        BigDecimal b = new BigDecimal(Double.toString(v));
        BigDecimal one = new BigDecimal("1");
        return b.divide(one, scale, BigDecimal.ROUND_DOWN).doubleValue();
    }

    /**
     * <p>
     * 浮点类型的“元”转换为long类型的“分”。
     * 
     * 具体转换算法位： 浮点类型乘以1000，四舍五入后取整，再除以10，取整即可
     * 
     * 例如：100.6699999，乘以1000变为100669.999， 四舍五入后为100670，再除以10，取整，为10067
     * 
     * 这样可以避免100.4459999取整为100.45
     * 
     * @param amount
     * @return
     */
    public static long yuan2fen(Double amount) {
        if (amount == null) {
            return 0L;
        }

        double d1 = amount * 1000;
        long l1 = Math.round(d1);
        double d2 = l1 / 10.0;
        return (long) d2;
    }

    /**
     * 元转分并合成为12位字符串
     * 
     * @param amount
     * @return
     */
    public static String yuan2fen12(Double amount) {
        if (amount == null) {
            return "000000000000";
        }

        double d1 = amount * 1000;
        long l1 = Math.round(d1);
        long result = new Double(l1 / 10.0).longValue();
        int length = String.valueOf(result).length();
        String resultStr = "";
        for (int i = 0; i < (12 - length); i++) {
            resultStr += "0";
        }
        return resultStr + result;
    }

    /**
     * 返回一定范围内的随机整数
     * 
     * @param min
     * @param max
     * @return
     */
    public static int random(int min, int max) {
        Random r = new Random();
        int i = r.nextInt(max - min) + min;
        return i;
    }

    /**
     * 格式化两位小数(金额)
     **/
    public static String formatTwoDecimal(double d) {
        return String.format("%.2f", d);
    }

    /**
     * 四舍五入
     * 
     * @param amount
     * @return
     */
    public static double halfUp(double amount) {
        return new BigDecimal(amount).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
    }
    
    /**
     * 金额四舍五入处理
     * 
     * @param amount
     * @return
     */
    public static double getDoubleAmount(double amount){
		if(amount <= 0){
			return 0;
		}
		
		return new BigDecimal(amount).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
	}
    
    public static void main(String[] args) {
        BigDecimal d1 = new BigDecimal(-100);
        BigDecimal d2 = new BigDecimal(3);
        System.out.println(d1.divide(d2, 2, BigDecimal.ROUND_CEILING));
        System.out.println(d1.divide(d2, 2, BigDecimal.ROUND_DOWN));
        System.out.println(d1.divide(d2, 2, BigDecimal.ROUND_FLOOR));
    }
}
